package com.rest;
import com.bpack.R;
import java.util.ArrayList;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.ListActivity;
import android.os.Bundle;

/**
 * JsonParse
 * Manages all incoming JSON objects requested by the BpackConnect class. 
 * There is a specialized method for each type of JSON 
 * This class has private variables that hold the data contained in JSON 
 * after they've been parsed.
 * Standard Procedure for handling JSON
 * -JSON comes in a string.
 * -Convert it to an object
 * -Store values into private variables or return the array to the caller.
 * @author Daranhdara Hun
 */
public class JsonParse extends ListActivity {
	JSONObject jObj;

	// 2D Array holding data about a specific item
	public String[][] item = new String[4][1];

	/*
	 *  These next 4 Array's are for the ToDo list
	 */
	private JSONArray toDoCategories; // Holds list of category names
	private JSONArray jarr[][]; // Holds the JSONArray contained in lines
	private String categData[][]; // 2d Array of all categoryName,templates,count,RKey, within each category except for the lines
	private int catCount[]; // holds the count of lines in each under each category

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
	}

	/** 
	 * parseMachine
	 * Customized method for parsing JSON's from the To Do list. 
	 * Parses JSON and populates the following three variable : toDOCategories, jarr[][], categData[][],
	 * @param json - JSON string obtained from the application RESTful call.
	 */
	public void parseMachine(String json){
		try {
			// Must convert json string to JSONObject
			jObj = (JSONObject) (new JSONObject(json)).get("data");

			// Populate the array with list of ToDo Categories
			toDoCategories = jObj.names();

			// Instantiate a JSONArray object to hold the array contained in the "lines" object
			jarr = new JSONArray[toDoCategories.length()][1];

			// Instantiates 2D array. Each initial index holds an array of size 4 to hold the 4 remaining objects after the "lines" object
			categData = new String[toDoCategories.length()][4];

			/*
			 * Populates the previous two variables with information from JSON
			 */
			for (int i=0; i<toDoCategories.length(); i++){
				int j = 0;
				// Gets the category name, Gets the object corresponding to category name, tmp is a JSONObject of each category/data
				JSONObject tmp = (jObj.getJSONObject(toDoCategories.optString(i))); 
				// Gets "lines" JSONArray of that object and passes into jarr array at matching index
				jarr[i][0] = tmp.getJSONArray("lines");
				// Loads the array
				categData[i][j] = tmp.optString("title");j++;
				categData[i][j] = tmp.optString("template");j++;
				categData[i][j] = tmp.optString("count");j++;
				categData[i][j] = tmp.optString("rkey");j++;				
			}
		}

		/*
		 * Thrown to indicate a problem with the JSON API. Such problems include:
		 * -Attempts to parse or construct malformed documents
		 * -Use of null as a name
		 * -Use of numeric types not available to JSON, such as NaNs or infinities.
		 * -Lookups using an out of range index or nonexistant name
		 * -Type mismatches on lookups
		 */
		catch (JSONException e) {
			e.printStackTrace();
			// Although this is a checked exception, it is rarely recoverable. 
			// Most callers should simply wrap this exception in an unchecked exception and rethrow:
			throw new RuntimeException(e);
		}
	}

	/** 
	 * getLineValue
	 * Searched the JSONObject for the key value and returns it
	 * Caution: This method cannot find key names in sub-objects. It can only see the immediate object
	 * @param key - (String) The key used to access the JSONArray
	 * @param lineOb - (JSONObject) The JSONArray being searched
	 * @return value - (String) value found from the JSONArray
	 */
	private String getLineValue(String key, JSONObject lineOb){
		try {
			return lineOb.getString(key);
		} catch (JSONException e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
	}

	/** 
	 * templateParser
	 * Given a string template with PHP variables, templateParser will
	 * search the template, replacing the PHP variables with their actual variables obtained from 
	 * the provided object.
	 * @param template - (String) String to be searched.
	 * @param jo - (JSONObject) An object containing the values to replace the variables.
	 * @return value - (String) a string of the translated template. 
	 */
	private String templateParser(String template, JSONObject jo){
		String finalStr = ""; // finalStr is the final string to be returned
		int i = 0; 
		while (i<template.length()-1){
			String key = "";
			
			//Create a two character string
			StringBuilder s = new StringBuilder();
			s.append(template.charAt(i));
			s.append(template.charAt(i+1));
			
			/*
			 *  Compare them, if true, start storing characters. We're only checking for consecutive pairs of "${"
			 *  because this is how a PHP variable starts off.
			 */
			if (s.toString().equals("${")){
				i = i + 2;
				StringBuilder str = new StringBuilder();
				// This is where we get the PHP variable
				while (!(str.append(template.charAt(i)).toString().equals("}"))){
					key += str.toString();
					i++;
					str.delete(0, 1);
				}
				finalStr += getLineValue(key, jo); // Append to the string
			}
			else {
				// add all characters in between variables. The characters in between the variables are part of the final string. 
				StringBuilder str = new StringBuilder();
				finalStr += str.append(template.charAt(i)).toString();
			}

			i++;
		}
		return finalStr;
	}

	/** templateProcessor
	 * matches each template with the right lines items, running through every lines item and returning the translated/decoded 
	 * string into an Arraylist
	 * This method calls the other helper functions.  
	 * @return finStr - ArrayList<String> of the decoded templates with the template variables replaced with the actual values.
	 */
	public ArrayList<String> templateProcessor(){ 
		ArrayList<String> finStr = new ArrayList<String>();
		JSONObject jObj = new JSONObject();
		catCount = new int[jarr.length];
		for (int i=0; i<jarr.length; i++){
			// Install number of lines for each category
			catCount[i] = jarr[i][0].length();
			// Grab each of line's objects input into templateParser to get the decoded template
			for (int j=0; j<jarr[i][0].length(); j++){
				try{
					jObj = jarr[i][0].getJSONObject(j);
				}
				catch(JSONException e) {
					e.printStackTrace();
					throw new RuntimeException(e);
				}
				try {
					finStr.add(templateParser(categData[i][1], jObj.getJSONObject("values")));
				} catch (JSONException e) {
					e.printStackTrace();
					throw new RuntimeException(e);
				}
			}
		}
		return finStr;
	}


	/**
	 * parseToDoItems
	 * This method, like the parseMachine, specifically parses only Items of the To Do list. 
	 * @param json - JSON String
	 */
	public String[][] parseToDoItems(String json){
		try {
			// Get labels and data
			JSONObject labels = (JSONObject) (new JSONObject(json)).get("labels");
			JSONObject data = (JSONObject) (new JSONObject(json)).get("data");

			// Get the key of the labels object and data object
			JSONArray labelArr = labels.names();
			JSONArray dataArr = data.names();

			// Declare temporary arrays
			String[] tmp1 = new String[labels.length()];
			String[] tmp11 = new String[labels.length()];
			String[] tmp2 = new String[data.length()];
			String[] tmp21 = new String[data.length()];

			// Iterate through array to get all data and store in array
			for (int i=0; i<labelArr.length(); i++){
				tmp1[i] = labelArr.getString(i);
				tmp11[i] = labels.optString(tmp1[i]);
			}
			for (int i=0; i<dataArr.length(); i++){
				tmp2[i] = dataArr.getString(i);
				tmp21[i] = data.optString(tmp2[i]);
			}
			
			item[0] = tmp1;
			item[1] = tmp11;
			item[2] = tmp2;
			item[3] = tmp21;
			return item;
			
		} catch (JSONException e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}



	}

	/***************************************************************************************Getters*/
	/***********************************************************************************************/

	/** getToDoCategories
	 *  Getter function
	 *  @return toDoCategories - JSONArray of all the ToDo Categories
	 */
	public JSONArray getToDoCategories(){
		return toDoCategories;
	}

	/** getCategoryData
	 * Getter function
	 * @return categData - 2d array of Category data independant of lines
	 */
	public String[][] getCategoyData(){
		return categData;
	}

	/** 
	 *  getCatName
	 *  Access the 2d String array categData and returns the Category Name
	 *  @param i = index of Array
	 *  @return Category name - String type
	 */
	public String getCatName(int i){
		return categData[i][0];
	}

	/** 
	 *  getTemplate
	 *  @returns template - a string template of how the text should be laid out. 
	 */
	public String getTemplate(int i) {
		return categData[i][1];
	}

	/** 
	 *  getCount
	 *  @returns count - the String value of count. 
	 */
	public String getCount(int i) {
		return categData[i][2];
	}

	/** 
	 *  getRKey
	 *  @returns count - the String value of RKey. 
	 */
	public String getRKey(int i) {
		return categData[i][3];
	}

	/** 
	 *  getCatCount()
	 *  @param i - index
	 *  @return catCount
	 */
	public int getCatCount(int i){
		return catCount[i];
	}

	/**
	 *  getChildString
	 *  Returns the String value of the key you're searching for. 
	 *  @param parent - parent index
	 *  @param child - child index
	 *  @param key - name of string value you want (ie. "ORDERID", "ID", "LABEL", "USERNAME"...)
	 *  @return child label - label of child at that index.
	 */
	public String getChildString(int parent, int child, String key){
		JSONArray tmp = jarr[parent][0];
		try {
			JSONObject ob = (JSONObject) tmp.get(child);
			JSONObject ob1 = (JSONObject) ob.get("values");
			return (String) ob1.get(key);
		} catch (JSONException e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
	}
}
